<?php
/**
 * Created by PhpStorm.
 * User: s.utkin
 * Date: 13.11.2014
 * Time: 17:28
 */
namespace Multilang;

use Pinenut\Model2\Finder;
use Multilang\TranslateEntities\History;

class TranslateEntities extends \Model {

	/**
	 * Символьный идентификатор переводимой сущности
	 *
	 * @var string
	 */
	public $code;

	/**
	 * Экшн, в котором переводится сущность
	 *
	 * @var string
	 */
	public $action;

	/**
	 * Массив с чистовиками<br>
	 * Формат:<br>
	 * [<br>
	 * 'langid_1' => 'translated text',<br>
	 * 'langid_2' => 'translated text',<br>
	 * ...<br>
	 * 'langid_N' => 'translated text'<br>
	 * ]
	 *
	 * @var array
	 */
	public $translateMain;

	/**
	 * Массив с черновиками<br>
	 * Формат:<br>
	 * [<br>
	 * 'langid_1' => 'translated text',<br>
	 * 'langid_2' => 'translated text',<br>
	 * ...<br>
	 * 'langid_N' => 'translated text'<br>
	 * ]
	 *
	 * @var array
	 */
	public $translateDraft;

	public $index;

	function indexes() {
		$languageIds = \MultilangConfig::getLanguageCodes();

		$index = [
			'actionCodeIndex' => [
				'action' => Finder::ORDER_ASC,
				'code' => Finder::ORDER_ASC,
			]
		];

		foreach ($languageIds as $langId) {
			$index['searchIndex_' . $langId]['index.' . $langId] = Finder::ORDER_ASC;
		}

		return array_merge(parent::indexes (), $index);
	}

	/**
	 * Поля модели
	 *
	 * @return array
	 */
	static function fields() {
		return array_merge(parent::fields(), 
			[
				'code' => self::STRING,
				'action' => self::STRING,
				'translateMain' => self::MIXED,
				'translateDraft' => self::MIXED,
				'index' => self::MIXED
			]);
	}

	public function isNeedTranslate($langId) {
		return ! isset($this->translateMain[$langId]) &&
			 ! isset($this->translateDraft[$langId]);
	}

	public function isNeedApprove($langId) {
		return isset($this->translateDraft[$langId]) && (! isset(
			$this->translateMain[$langId]) ||
			 $this->translateMain[$langId] != $this->translateDraft[$langId]);
	}

	public function isDone($langId) {
		return isset($this->translateDraft[$langId]) &&
			 isset($this->translateMain[$langId]) &&
			 $this->translateMain[$langId] == $this->translateDraft[$langId];
	}

	
	public static function getItemsForTranslate($ids, $query = '', $searchStrategy = 'pageAndHidden', $langId = null) {

		if(!is_array($ids))
		{
			$ids = explode(',', $ids);
		}

		$langId = $langId ?: \MultilangConfig::getDefaultLanguageCode();
		
		# Формируем обработчик стратегии поиска
		$searchStrategyHandler = 'searchStrategy' . ucfirst($searchStrategy);
		if (!method_exists(static::className(), $searchStrategyHandler)) {
			return [];
		}

		# Готовим файндер
		$finder = static::find();
		$query = trim($query);
		if (!empty($query)) {
			$queryList = static::prepareQueryStringToIndex($query);
			foreach ($queryList as &$item) {
				$item = new \MongoRegex ( '/^' . $item . '/' );
			}
			$finder->where('index.' . $langId, $queryList, Finder::OP_ALL);
		}

		# Ищем элементы
		$result = static::$searchStrategyHandler($ids, $finder);

		# Сортируем элементы
		usort($result, function ($a, $b) use ($langId)
		{
			$aTitle = mb_strtolower($a->action . ' ' . $a->getTitle($langId), 'utf-8') ;
			$bTitle = mb_strtolower($b->action . ' ' . $b->getTitle($langId), 'utf-8');

			if ($aTitle == $bTitle) {
				return 0;
			}
			return ($aTitle < $bTitle) ? -1 : 1;
		});

		return $result;
	}

	/**
	 * Находит сущность для перевода по её символьному коду и имени экшена.
	 * Если сущность не найдена - создается пустая.
	 *
	 * @param $entityCode - символьный код сущности
	 * @param $actionName - имя экшена
	 * @return TranslateEntities
	 */
	public static function getByCodeAndAction($entityCode, $actionName)
	{
		# Находим переводимую сущность по коду
		$finder = TranslateEntities::find();
		$finder->where('code', $entityCode);
		$finder->where('action', $actionName);
		/** @var TranslateEntities $entityModel */
		$entityModel = $finder->one();

		# Если не нашли в БД сущность - создаем ее
		if (!$entityModel) {
			$entityModel = new TranslateEntities();
			$entityModel->code = $entityCode;
			$entityModel->action = $actionName;
			$entityModel->save();
			// для корректной работы инвалидации (а в этой ситуации происходит косяк - теряется сущность, 
			// т.к. инвалиируется по item_id, а в селекте этот тэг не выставляется) нужно выставлять этот тэг 
			// либо перезапросив сущность, либо в инсерте выставлять тэг (странный кейс)
			
		}

		return $entityModel;
	}

	/**
	 * Аппрувит перевод (сохраняет черновик в чистовик)
	 * 
	 * $itemsIds массив с айдишниками
	 * 
	 * @param array $itemsIds
	 */
	public function approve($itemsIds, $langId, $identity)
	{
		// Если все ок - перебираем массив с ID-шниками
		// вытягиваем записи и сохраняем данные в "чистовик". 
		if(!is_array($itemsIds) || count($itemsIds) == 0)
		{
			return;
		}

		foreach ($itemsIds as $itemId)
		{
			/** @var TranslateEntities $modelItem */
			$modelItem = TranslateEntities::find($itemId);
			$modelItemDraft = $modelItem->translateDraft[$langId];
			History::add($identity, 3, $itemId, $langId, $modelItemDraft, $modelItem->translateMain[$langId]);
			$modelItem->translateMain[$langId] = $modelItemDraft;
			$modelItem->save();
		}
	}
	
	/**
	 * Удаляет запись
	 *
	 * $itemsIds массив с айдишниками
	 *
	 * @param array $itemsIds
	 */
	public function removeItem($itemsIds)
	{
		// Если все ок - перебираем массив с ID-шниками
		// вытягиваем записи и удаляем их.
		if(!is_array($itemsIds) || count($itemsIds) == 0)
		{
			return;
		}
	
		foreach ($itemsIds as $itemId)
		{
			/** @var TranslateEntities $modelItem */
			$modelItem = TranslateEntities::find($itemId);

			History::removeItem($itemId);
			
			$modelItem->remove();
		}
	}

	public function getTitle($langId = null)
	{
		$langId = $langId ?: \MultilangConfig::getDefaultLanguageCode();
		$title =  $this->code;

		if(isset($this->translateDraft[$langId]))
		{
			$title = $this->translateDraft[$langId];
		}
		elseif(isset($this->translateMain[$langId]))
		{
			$title = $this->translateMain[$langId];
		}

		return $title;
	}

	public function getIndexTitle($langId = null)
	{
		$langId = $langId ?: \MultilangConfig::getDefaultLanguageCode();
		$title =  $this->code;
	
		if(isset($this->translateDraft[$langId]))
		{
			$title .= ' ' . $this->translateDraft[$langId];
		}
		
		if(isset($this->translateMain[$langId]))
		{
			$title .= ' ' . $this->translateMain[$langId];
		}
	
		return $title;
	}
	
	
	public static function prepareQueryStringToIndex($string)
	{
		$title = mb_strtolower($string, 'utf-8');
		$title = preg_replace('/\W+/u', ' ', $title);
		$indexData = explode(' ', $title);
		$indexData = array_filter($indexData);
		return array_values(array_unique($indexData));
	}

	public function updateIndex($langId, $save = true) {

		$indexData = static::prepareQueryStringToIndex($this->getIndexTitle($langId));

		$this->index[$langId] = $indexData;

		if ($save) {
			$this->save();
		}
	}

	public function updateAllIndexes($save = true)
	{
		$languageIds = \MultilangConfig::getLanguageCodes();

		foreach ($languageIds as $langId) {
			$this->updateIndex($langId, false);
		}

		if ($save) {
			$this->save();
		}
	}

	public function beforeSave() {
		$this->updateAllIndexes(false);
	}

	public static function searchStrategyPage($ids, $finder)
	{
		if (!count($ids)) {
			return [];
		}

		/** @var TranslatedEntities $actions */
		return $finder
			->where('_id', (array) $ids, Finder::OP_IN)
			->all();
	}

	public static function searchStrategyPageAndHidden($ids, $finder)
	{
		if (!count($ids)) {
			return [];
		}

		// для того, чтобы учитывать все переводы в панеле - собираем не переводы,
		// а действия в которых есть переводы, и уже в панели достаём по ним все переводы

		/** @var TranslatedEntities $actions */
		$actions = static::find()
			->where('_id', (array) $ids, Finder::OP_IN)
			->column('action');

		$actions = array_unique($actions);

		return $finder
			->where('action', $actions, Finder::OP_IN)
			->all();
	}

	public static function searchStrategyAll($ids, $finder)
	{
		return $finder->all();
	}
}